use anyhow::{Context, Result};
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;
use crate::config::Mapping;
use globset::{Glob, GlobSet, GlobSetBuilder};
use walkdir::{WalkDir,DirEntry};
use tracing::{info} ;
use crate::utils::* ;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
    Push, // source -> destination
    Pull, // destination -> source
}

impl Direction {
    pub fn action_str(&self) -> &'static str{
        match self {
            Direction::Push => "驱逐",
            Direction::Pull => "召回",
        }
    }
}

fn build_glob_set(patterns: &[String]) -> Result<GlobSet> {
    let mut builder = GlobSetBuilder::new();
    for p in patterns {
        builder.add(Glob::new(p)
            .context(format!("无效的 glob 模式: {}", p))?);
    }
    builder.build().context("构建 globset 失败")
}

pub fn sync(mapping: &Mapping, direction: Direction, delete_source: bool) -> Result<()> {
    let (source_root, dest_root) = match direction {
        Direction::Push => (&mapping.source, &mapping.destination),
        Direction::Pull => (&mapping.destination, &mapping.source),
    };


    info!("{} {} -> {}", direction.action_str() , source_root.display(), dest_root.display());


    fs::create_dir_all(dest_root).context("无法创建目标根目录")?;

    // 构建 include / exclude 匹配器
    let include_set = build_glob_set(&mapping.include)?;
    let exclude_set = build_glob_set(&mapping.exclude)?;

    // 定义目录过滤函数
    let filter_dir = |e: &DirEntry| -> bool {
        if e.file_type().is_dir() {
            if let Some(name) = e.file_name().to_str() {
                if !exclude_set.is_empty() && exclude_set.is_match(name) {
                    info!("跳过目录: {}", e.path().display());
                    return false; // 返回 false 阻止进入该目录
                }
            }
        }
        true
    };

    for entry in WalkDir::new(source_root)
        .min_depth(1)
        .into_iter()
        .filter_entry(filter_dir)
        .filter_map(|e| e.ok())
    {
        let source_path = entry.path();
        let relative_path = source_path.strip_prefix(source_root)
            .context("路径前缀不匹配")?;
        let dest_path = dest_root.join(relative_path);

        if source_path.is_dir() {
            // 目录过滤：如果命中 exclude 规则，跳过整个目录
            let dir_name = source_path.file_name().and_then(|n| n.to_str()).context("目录名无效")?;
            if !exclude_set.is_empty() && exclude_set.is_match(dir_name) {
                info!("跳过目录: {}", source_path.display());
                continue; // 跳过这个目录
            }

            // 创建目标目录
            fs::create_dir_all(&dest_path)
                .with_context(|| format!("创建目录失败: {}", dest_path.display()))?;
        } else if source_path.is_file() {
            let file_name = source_path.file_name().and_then(|n| n.to_str()).context("文件名无效")?;

            // 文件过滤
            let matched = include_set.is_empty() || include_set.is_match(file_name);
            let excluded = !exclude_set.is_empty() && exclude_set.is_match(file_name);

            if matched && !excluded {  // 匹配且不排除的文件
                if !dest_path.exists() || is_file_modified(source_path, &dest_path)? {
                    if let Some(parent) = dest_path.parent() {
                        fs::create_dir_all(parent)
                            .with_context(|| format!("创建父目录失败: {}", parent.display()))?;
                    }

                    fs::copy(source_path, &dest_path)
                        .with_context(|| format!("复制文件失败: {}", source_path.display()))?;
                    info!("复制: {}", source_path.display());

                }
            }
        }
    }

    // 复制完成之后 根据额外要求判断是否需要直接删除机载SSD的内容
    if direction == Direction::Push && delete_source {
        fs::remove_dir_all(source_root)
            .with_context(|| format!("驱逐成功但删除机载数据失败: {}", source_root.display()))?;
        info!("已删除源文件: {}", source_root.display());
    }

    // if delete {  // 根据mapping设置的同步规则再查看
    //     // TODO: 删除目标目录中源目录不存在的文件
    // }
    info!("同步完毕");
    Ok(())
}


